//
// LoaderTask.cpp
//

#include "LoaderTask.h"

CLoaderTaskQueue::CLoaderTaskQueue(void)
{
	::InitializeCriticalSection(&_cs);
	_hQueued = ::CreateEvent(NULL, TRUE, FALSE, NULL);
	_hWorker = NULL;
}

CLoaderTaskQueue::~CLoaderTaskQueue(void)
{
	::DeleteCriticalSection(&_cs);
	CloseHandle(_hQueued);
	if(_hWorker) ::TerminateThread(_hWorker, 0);
}

bool CLoaderTaskQueue::addTask(CLoaderTask *pTask)
{
	LOG_WRITE(DS_LOADER_TASK_ACCEPTED);
	::EnterCriticalSection(&_cs);
	_tasks.push(pTask);
	SetEvent(_hQueued);
	::LeaveCriticalSection(&_cs);
	return execute();
}

static DWORD WINAPI thread_entry(__in LPVOID lpParameter)
{
	((CLoaderTaskQueue *)lpParameter)->_thread_callback_worker();
	::ExitThread(0);
	return 0;
}

bool CLoaderTaskQueue::execute(void)
{
	if(_hWorker) return true;
	_hWorker = CreateThread(NULL, 0, (LPTHREAD_START_ROUTINE)thread_entry, (LPVOID)this,
		0, NULL);
	if(_hWorker == NULL) {
		LOG_WRITE(DS_CREATE_THREAD_FAILED, GetLastError());
		return false;
	}
	return true;
}

void CLoaderTaskQueue::_thread_callback_worker(void)
{
	DWORD dwState;
	CLoaderTask *task;

	while(1) {
		dwState = WaitForSingleObject(_hQueued, INFINITE);
		if(dwState == WAIT_OBJECT_0) {
			EnterCriticalSection(&_cs);
			if(_tasks.empty()) {
				ResetEvent(_hQueued);
				LeaveCriticalSection(&_cs);
			} else {
				task = _tasks.top();
				_tasks.pop();
				LeaveCriticalSection(&_cs);
				task->begin();
				SetEvent(task->_ref->complete);
			}
		} else {
			// froze 10 sec.
			Sleep(10000);
		}
	}
}
